Skip to content

5.2 HttpContext

📝 模块更新日志 新特性*

+ 新增 `HttpContext` 获取客户端 `IPv4` 地址的 `GetRemoteIpAddressToIPv4` 方法 `xff` 参数 4\.9\.4\.3 ⏱️2024\.07\.01 [c280dfd](https://gitee.com/dotnetchina/Furion/commit/c280dfda3a7e6758c5e09b341910344090b22c60)
  • 问题修复

    • 修复 HttpRequest.GetRequestUrlAddress 拓展获取请求地址丢失端口号问题 4.9.4.5 ⏱️2024.07.11 6df5dbd
    • 修复 启用请求 Body 重复读且在授权之前读取导致非 GET/HEAD/OPTION 请求异常 4.8.7.15 ⏱️2023.03.19 #I6NX9E

5.2.1 关于 HttpContext

ASP.NET 的时代,我们通常通过 HttpContext 全局静态类获取请求上下文,但在 ASP.NET Core 中,HttpContext 是一个非静态的抽象类,无法手动创建,也无法通过静态获取。

虽然在 ASP.NET Core 中无法直接获取 HttpContext 对象。但是微软也提供了注入 IHttpContextAccessor 方式获取。

5.2.2 获取 HttpContext

ASP.NET CoreFurion 提供了多种访问 HttpContext 的方式。

5.2.2.1 在 ControllerBase 派生类中

ControllerBase 派生类中,我们可以直接通过 HttpContext 属性获取 HttpContext 对象。

public class HomeController : Controller  
{  
    public IActionResult Index()  
    {  
        // 在这里HttpContext 是 Controller/ControllerBase 对象的属性  
        var httpContext = HttpContext;  

        return View();  
    }  
}  

5.2.2.2 注入 IHttpContextAccessor

Furion 框架中,默认已经注册了 IHttpContextAccessor 服务,所以我们可以通过构造函数注入该接口获取。

public class AppService  
{  
    public AppService(IHttpContextAccessor httpContextAccessor)  
    {  
        var httpContext = httpContextAccessor.HttpContext;  
    }  
}  

5.2.2.3 通过 App.HttpContext

App 静态类也提供了 App.HttpContext 获取 HttpContext 对象。

var request = App.HttpContext.Request;  

Web 中访问在 Web 完整的生命周期内,App.HttpContext 都是有效的,但在非 Web 中返回 null,避免在多线程,事件总线,定时任务等中使用。

5.2.3 HttpContext 拓展方法

Furion 框架基于 HttpContext 提供了一些常用的拓展方法。

5.2.3.1 获取当前请求的特性 Attribute

下列代码通常用于授权 Handler 中。

var attribute = httpContext.GetMetadata<SomeAttribute>();  

Middleware 中间件获取特性方式在 Middleware 中间件中获取有所区别,主要通过 HttpContextFeatures 获取,如:

var endpointFeature = httpContext.Features.Get<IEndpointFeature>();  
var attribute =  endpointFeature?.Endpoint?.Metadata?.GetMetadata<SomeAttribute>();  

5.2.3.2 设置 Swagger 自动授权

Swagger 默认不能记住授权信息,一旦刷新浏览器就自动清空,所以 Furion 提供了该拓展,即使刷新浏览器也能保持授权状态。

// 检查用户登录和生成 token 代码...  
// .....  

// 之后调用该拓展,这样就可以实现 Swagger 刷新也能记住登录了  
httpContext.SigninToSwagger("你的token");  

5.2.3.3 退出 Swagger 授权

通过后端代码强制性让 Swagger 授权实现,只针对下一次请求有效!

httpContext.SignoutToSwagger();  

5.2.3.4 获取本地 IP 地址

// ipv4  
var ipv4 = httpContext.GetLocalIpAddressToIPv4();  

// ipv6  
var ipv6 = httpContext.GetLocalIpAddressToIPv6();  

5.2.3.5 获取客户端 IP 地址

// ipv4  
var ipv4 = httpContext.GetRemoteIpAddressToIPv4();  // Furion 4.9.4.3+ 版本支持设置 xff: true,优先获取请求头 X-Forwarded-For 转发的 IP 地址   

// ipv6  
var ipv6 = httpContext.GetRemoteIpAddressToIPv6();  

获取不到真实 IP 处理使用了 Nginx 反向代理后可能会出现获取不到客户端真实的 IP 地址,这时需要在 Startup.cs 中添加 IP 地址转发配置:

public void Configure(IApplicationBuilder app, IWebHostEnvironment env)  
{  
    app.UseForwardedHeaders(new ForwardedHeadersOptions  
    {  
        ForwardedHeaders = ForwardedHeaders.XForwardedFor | ForwardedHeaders.XForwardedProto  
    });  

    // 其他代码...  
}  


如果添加以上配置之后获取的还是 Nginx 代理服务器的地址,那么可以尝试使用以下配置:

// 注册服务  
services.Configure<ForwardedHeadersOptions>(options =>  
{  
    options.ForwardedHeaders = ForwardedHeaders.All;  
    options.KnownNetworks.Clear();  
    options.KnownProxies.Clear();  
});  

// 中间件(确保第一个注册)  
app.UseForwardedHeaders();  // 无需参数  

5.2.3.6 设置响应头 Token

httpContext.SetTokensOfResponseHeaders("token", "刷新token");  

5.2.4 读取 Body 内容(重复读)

版本说明以下内容仅限 Furion 4.7.9 + 版本使用。

默认情况下,ASP.NET Core 不支持重复读取 Body 内容,Furion 框架提供了拓展方法,需要按照以下步骤操作:

  1. Startup.csConfigure 启用 Body 重复读功能

  2. .NET5 版本:

public void Configure(IApplicationBuilder app, IWebHostEnvironment env)  
{  
    // ...  
    app.EnableBuffering();  
    app.UseRouting();  
    // ....  
}  

  • .NET6+ 版本:
var builder = WebApplication.CreateBuilder(args).Inject();  
// ...  
var app = builder.Build();  
// ...  
app.UseInject();  

app.EnableBuffering();  
app.MapControllers();  

app.Run();  

注意:app.EnableBuffering() 必须在 app.UseRouting()app.MapControllers() 之前注册。

  1. 使用 HttpContextHttpRequest 拓展 .ReadBodyContentAsync() 即可
// HttpContext 拓展  
var body = await httpContext.ReadBodyContentAsync();  

// HttpRequest 拓展  
var body = await httpContext.Request.ReadBodyContentAsync();  

特别注意如果使用了 AddJsonOptionsAddNewtonsoftJson 序列化服务,那么请确保它们在 .AddInjectXXX 之前注册。

5.2.5 反馈与建议

与我们交流给 Furion 提 Issue